﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphViewer.Entity;
using GraphViewer.View;
using System.IO;
using System.Diagnostics;
using System.Configuration;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml;
using GraphViewer.Data;
using System.Threading.Tasks;
using System.Threading;

namespace GraphViewer
{
    public class ExecutionControl
    {
        public static ExecutionControl Instance = new ExecutionControl();
        public string ProcessForceError = null;
        public List<string> Groups = new List<string>();
        public Dictionary<string, List<ProcessEntity>> Processes = new Dictionary<string, List<ProcessEntity>>();
        private object _locker = new object();

        public void Save(string groupId)
        {
            lock (_locker)
            {
                if (Processes.ContainsKey(groupId))
                {
                    XDocument document = new XDocument();
                    XmlSerializer s = new XmlSerializer(typeof(List<ProcessEntity>));
                    XmlWriter writer = document.CreateWriter();
                    s.Serialize(writer, Processes[groupId]);
                    writer.Close();
                    document.Save(string.Format(@"execucao_{0}.xml", groupId));
                }
            }
        }

        public void Open(string groupId)
        {
            lock (_locker)
            {
                if (File.Exists(string.Format(@"execucao_{0}.xml", groupId)))
                {
                    XDocument document = XDocument.Load(string.Format(@"execucao_{0}.xml", groupId));
                    XmlSerializer s = new XmlSerializer(typeof(List<ProcessEntity>));
                    XmlReader reader = document.CreateReader();

                    if (Processes.ContainsKey(groupId))
                        Processes.Remove(groupId);

                    Processes.Add(groupId, (List<ProcessEntity>)s.Deserialize(reader));
                    reader.Close();
                }
            }
        }

        public void Log(string groupId, string processId, string log)
        {
            lock (_locker)
            {
                string logFile = @"erro.txt";

                File.AppendAllText(logFile, groupId.ToString().PadRight(10) + processId.ToString().PadRight(10) + DateTime.Now.ToString() +System.Environment.NewLine);
                File.AppendAllText(logFile, log + System.Environment.NewLine);
                File.AppendAllText(logFile, System.Environment.NewLine);
            }
        }

        public List<ProcessEntity> GetProcesses(string groupId)
        {
            List<ProcessEntity> processes = new List<ProcessEntity>();

            lock (_locker)
            {
                if (Processes.ContainsKey(groupId))
                {
                    processes = Processes[groupId];
                }
            }

            return processes;
        }

        public void AddProcess(string groupId, ProcessEntity process)
        {
            lock (_locker)
            {
                if (!Processes.ContainsKey(groupId))
                    Processes.Add(groupId, new List<ProcessEntity>());

                Processes[groupId].Add(process);
            }
        }

        public void Execute(DataLoader dataLoader, string mtsServerName, string dataBase)
        {
            List<Task> tasks;

            CancellationTokenSource tokenSource = new CancellationTokenSource();

            foreach (var group in dataLoader.Groups.Where(g => g.Dependencies.Count == 0))
            {
                group.TokenSource = tokenSource;
                group.ExecutionGroup = new ExecutionGroup(dataLoader, group, mtsServerName, dataBase, group.TokenSource);
                group.Task = new Task(group.ExecutionGroup.Execute, group.TokenSource.Token);
            }

            foreach (var group in dataLoader.Groups.Where(g => g.Dependencies.Count != 0))
            {
                tasks = new List<Task>();

                foreach (string dependency in group.Dependencies)
                {
                    GroupEntity groupDependency = dataLoader.Groups.Find(g => g.GroupId == dependency);
                    if (groupDependency != null && group.Dependencies.Count > 0 && groupDependency.Task != null)
                        tasks.Add(groupDependency.Task);
                }

                group.ExecutionGroup = new ExecutionGroup(dataLoader, group, mtsServerName, dataBase, tokenSource);
                group.Task = Task.Factory.ContinueWhenAll(tasks.ToArray(), group.ExecutionGroup.Execute, tokenSource.Token);
            }

            foreach (var group in dataLoader.Groups.Where(g => g.Dependencies.Count == 0))
            {
                group.Task.Start();
            }

            try
            {
                GroupEntity lastGroup = dataLoader.Groups.Find(g => g.GroupId == "21");
                if (lastGroup != null) lastGroup.Task.Wait();
            }
            catch
            {

            }
        }
    }
}
